﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace DvtCap
{
	public enum hw_codec_id
	{
		codec_id_mjpg = 7,       //mjpg解码   
		codec_id_h264 = 27,      //h264解码
		codec_id_h265 = 173
	};
	public unsafe class DecoderWrapper
	{
		public const string LibraryName = "DvtCam.dll";

		[DllImport(DvtCamWrapper.LibraryName, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
		protected unsafe static extern int getWidth(void* handle);
		[DllImport(DvtCamWrapper.LibraryName, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
		protected unsafe static extern int getHeight(void* handle);
		[DllImport(DvtCamWrapper.LibraryName, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
		protected unsafe static extern void* getData(void* handle);
		[DllImport(DvtCamWrapper.LibraryName, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
		protected unsafe static extern void* CreateJepgDeocder(int pixelformat);
		[DllImport(DvtCamWrapper.LibraryName, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
		protected unsafe static extern void* CreateH264Deocder();
		[DllImport(DvtCamWrapper.LibraryName, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
		protected unsafe static extern void* CreateH265Deocder();
		[DllImport(DvtCamWrapper.LibraryName, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
		protected unsafe static extern void* CreateHW26XDeocder(void* window, int width, int height, int codecid);
		[DllImport(DvtCamWrapper.LibraryName, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
		protected unsafe static extern void DestroyDecoder(void* handle);
		[DllImport(DvtCamWrapper.LibraryName, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		protected unsafe static extern bool CDecode(void* handle, void* buf, int len);
		[DllImport(DvtCamWrapper.LibraryName, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
		protected unsafe static extern void getPtrYUV(void* handle, void** p0, void** p1, void** p2);
		[DllImport(DvtCamWrapper.LibraryName, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
		protected unsafe static extern void getStride(void* handle, int* stride0, int* stride1, int* stride2);
		[DllImport(DvtCamWrapper.LibraryName, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
		[return: MarshalAs(UnmanagedType.I1)]
		protected unsafe static extern bool HWdecoder_has_inited(void* handle);

		protected Bitmap bmp = null;
		protected void* decoder = null;
		~DecoderWrapper()
		{
			DestroyDecoder(decoder);
		}

		protected bool Decode(void* buf, int len)
		{
			return CDecode(decoder, buf, len);
		}

		public virtual bool decode(void* buf, int len)
        {
			return false;
        }
		public Bitmap getImage()
		{
			if (bmp != null)
			{
				return new Bitmap(bmp);
			}
			else
			{
				return null;
			}
		}
		public void* getData()
		{
			if (decoder != null)
			{
				return getData(decoder);
			}
			else
			{
				return null;
			}
		}
		public int getWidth()
		{
			return getWidth(decoder);
		}
		public int getHeight()
		{
			return getHeight(decoder);
		}

		public void getPtrYUV(byte** p0, byte** p1, byte** p2)
		{
			getPtrYUV(decoder, (void**)p0, (void**)p1, (void**)p2);
		}

		public void getStride(int* stride0, int* stride1, int* stride2)
		{
			getStride(decoder, stride0, stride1, stride2);
		}
	}

	public enum DJPF
	{
		DJPF_RGB = 0,
		DJPF_BGR,
		DJPF_RGBX,
		DJPF_BGRX,
		DJPF_XBGR,
		DJPF_XRGB,
		DJPF_GRAY,
		DJPF_RGBA,
		DJPF_BGRA,
		DJPF_ABGR,
		DJPF_ARGB,
		DJPF_CMYK,
		DJPF_UNKNOWN = -1
	};

	public unsafe class JpegDecoderWrapper : DecoderWrapper
	{
		public JpegDecoderWrapper(DJPF dJPF)
		{
			decoder = CreateJepgDeocder((int)dJPF);
		}

		public override unsafe bool decode(void* buf, int len)
		{
			if (Decode(buf, len))
			{
				if (bmp == null ||
					bmp.Width != getWidth() ||
					bmp.Height != getHeight())
				{
					bmp = new Bitmap(getWidth(), getHeight(), 4 * getWidth(), PixelFormat.Format32bppArgb, new IntPtr(getData()));
				}
				return true;
			}
			else
			{
				return false;
			}
		}
	}

	public unsafe class H264DecoderWrapper : DecoderWrapper
	{
		public H264DecoderWrapper()
		{
			decoder = CreateH264Deocder();
		}

		public override unsafe bool decode(void* buf, int len)
		{
			if (Decode(buf, len))
			{
				if (bmp == null ||
					bmp.Width != getWidth() ||
					bmp.Height != getHeight())
				{
					bmp = new Bitmap(getWidth(), getHeight(), PixelFormat.Format24bppRgb);
				}
				return true;
			}
			else
			{
				return false;
			}
		}

		//public void getPtrYUV(byte** p0, byte** p1, byte** p2)
		//      {
		//	getPtrYUV(decoder, (void**)p0, (void**)p1, (void**)p2);
		//}

		//public void getStride(int* Ystride, int* UVstride)
		//{
		//	int stride3 = 0;
		//	getStride(decoder, Ystride, UVstride, &stride3);
		//}

		public new Bitmap getImage()
		{
			BitmapData BD = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
			byte* p0, p1, p2;
			int Ystride, UVstride,stride2;
			getPtrYUV(&p0, &p1, &p2);
			getStride(&Ystride, &UVstride, &stride2);
			DvtCamWrapper.convertYUV420toBGR24(p0, p1, p2,
				BD.Scan0.ToPointer(),
				bmp.Width, bmp.Height,
				Ystride, UVstride,
				BD.Stride);
			bmp.UnlockBits(BD);
			return new Bitmap(bmp);
		}


	}

	public unsafe class HW26XDecoderWrapper : DecoderWrapper
	{
		public HW26XDecoderWrapper(IntPtr windowhandle, int w_codec, int h_codec, int codecid)
		{
			decoder = CreateHW26XDeocder(windowhandle.ToPointer(), w_codec, h_codec, codecid);
		}

		public override unsafe bool decode(void* buf, int len)
		{
			return Decode(buf, len);
		}

		public bool has_inited()
		{
			return HWdecoder_has_inited(decoder);
		}

	}

    public unsafe class H265DecoderWrapper : DecoderWrapper
    {
		public H265DecoderWrapper()
        {
			decoder = CreateH265Deocder();
        }
		public override unsafe bool decode(void* buf, int len)
        {
			if (Decode(buf, len))
			{
				if (bmp == null ||
					bmp.Width != getWidth() ||
					bmp.Height != getHeight())
				{
					int w = getWidth();
					int h = getHeight();
					bmp = new Bitmap(getWidth(), getHeight(), PixelFormat.Format24bppRgb);
				}
				return true;
			}
			else
			{
				return false;
			}
		}

		public new Bitmap getImage()
		{
			BitmapData BD = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
			byte* p0, p1, p2;
			int stride0, stride1, stride2;
			getPtrYUV(&p0, &p1, &p2);
			getStride(&stride0, &stride1, &stride2);
			DvtCamWrapper.convertYUV420toBGR24(p0, p1, p2,
				BD.Scan0.ToPointer(),
				bmp.Width, bmp.Height,
				stride0, stride1,
				BD.Stride);
			bmp.UnlockBits(BD);
			return new Bitmap(bmp);
		}
	}
}
